import type { ProgramAvailable, ProgramSelectOption } from '@/api/appliance'
import type { BaseController } from '@/controller/BaseAppliance/definition'
import { FINISH_IN_RELATIVE, START_IN_RELATIVE } from '@/constants/Command'
import dayjs from 'dayjs'
import { useAccountStore } from '@/store/account'
import i18n from '@/i18n'

// 获取预约类型 Start | TransformedStart | Finish
export type RelativeType = 'Start' | 'TransformedStart' | 'Finish'
export type RelativeData = {
  type: RelativeType
  /**
   * 预计开始或结束时间
   *  - type 为 Start 时: 显示预计结束时间
   *  - type 为 Finish 时: 显示预计开始时间
   */
  estimatedTime: string // 格式 00:00
  estimatedTimeLabel: string // "预计结束时间" | "预计结束时间"
  /**
   * 预约时间选择间隔 (单位: 秒)
   */
  stepSize: number
  // 获取预约启动时需要传参的时间
  getTimeValue: () => number
}

export type UseOrderTimeControl = ReturnType<typeof useOrderTime>
export function useOrderTime(control: BaseController.Control) {
  const accountStore = useAccountStore()

  // RELATIVE选项
  const relativeOption = computed(() => control.store.orderRelativeOption)
  // 是否将Finish in relative 转换显示为预计xx:xx开始
  const shouldTransformRelative = computed(() => control.store.transformRelativeOrderForced)
  // 程序时长
  const remaining = computed(() => control.store.programRemaining)

  /**
   * 选择时间
   */
  // 预约时间范围 (起始 ~ 截至 的秒数)
  const orderTimeRange = computed(() => {
    if (relativeOption.value) {
      const { max, min } = relativeOption.value.constraints
      return max - min
    }
    return 86400 // 默认24小时的秒数
  })
  const selectableStartTime = ref(getSelectableStartTime())
  const selectableEndTime = ref(getSelectableEndTime())
  // 获取可选的 预约时间选项 起始时间
  function getSelectableStartTime(delaySeconds = 0): number {
    // 默认起始时间为当前时间
    return dayjs().second(0).millisecond(0).add(delaySeconds, 'seconds').valueOf()
  }
  // 获取可选的 预约时间选项 结束时间
  function getSelectableEndTime(): number {
    return dayjs().second(0).millisecond(0).add(orderTimeRange.value, 'seconds').valueOf()
  }
  function initSelectableTime() {
    // 计算开始时间
    const delayStartTime = relativeData.value?.type === 'Finish' ? remaining.value : 0
    selectableStartTime.value = getSelectableStartTime(delayStartTime)
    // 计算结束时间
    let endTime = getSelectableEndTime()
    // 转换为开始时间的结束时间预约 需要减去Duration
    if (relativeData.value?.type === 'TransformedStart') {
      endTime = dayjs(endTime).subtract(remaining.value, 'seconds').valueOf()
    }
    selectableEndTime.value = endTime
  }

  // 时间选择
  const selectedTime = ref<number>(0)
  function setSelectTime(timestamp: number) {
    selectedTime.value = timestamp
  }

  // 当前选择时间 设为最早的开始时间
  function selectBeginTime() {
    setSelectTime(selectableStartTime.value)
  }
  // 当前选择时间 设为谷电开始时间后
  function selectValleyTime(options?: {
    // 当前在谷电时间内时 停留在当前时间 不做处理
    stayTimeWithinValleyTime?: boolean
  }) {
    // 获取谷电时间
    const [valleyStartHour, valleyStartMinute] = accountStore.valleyElecStartTime
      .split(':')
      .map((timeText) => parseInt(timeText))
    const [valleyEndHour, valleyEndMinute] = accountStore.valleyElecEndTime
      .split(':')
      .map((timeText) => parseInt(timeText))

    // 计算谷电时间
    let valleyStartDate = dayjs().hour(valleyStartHour).minute(valleyStartMinute).second(0).millisecond(0)
    let valleyEndDate = dayjs().hour(valleyEndHour).minute(valleyEndMinute).second(0).millisecond(0)
    // 谷时结束位于次日 结束时间加1天
    if (valleyEndDate.isBefore(valleyStartDate)) {
      valleyEndDate = valleyEndDate.add(24, 'hour')
    }
    // 谷时开始、谷电结束 都小于当前时间 尝试往后延1天再判断
    if (valleyStartDate.isBefore(dayjs()) && valleyEndDate.isBefore(dayjs())) {
      valleyStartDate = valleyStartDate.add(24, 'hour')
      valleyEndDate = valleyEndDate.add(24, 'hour')
    }

    switch (relativeData.value?.type) {
      case 'TransformedStart':
      case 'Start': {
        const selectTime = valleyStartDate.valueOf()
        selectableStartTime.value = getSelectableStartTime()
        // 判断是否需要停留在谷电时间内
        if (options?.stayTimeWithinValleyTime) {
          const currentTime = dayjs(selectedTime.value)
          // 需要停留在谷电时间内
          const shouldStayTime = !currentTime.isBefore(valleyStartDate) && !currentTime.isAfter(valleyEndDate)
          if (shouldStayTime) break
        }
        setSelectTime(selectTime)
        break
      }
      case 'Finish': {
        // 结束时间 取 谷电开始时间 + duration
        const selectTime = valleyStartDate.subtract(remaining.value, 'seconds').valueOf()
        selectableStartTime.value = getSelectableStartTime(remaining.value)
        setSelectTime(selectTime)
        break
      }
      default: {
        selectBeginTime()
        break
      }
    }
  }

  // 是否预约今天
  const isTodaySelected = computed(() => dayjs(selectedTime.value).date() === dayjs().date())

  /**
   * 相对开始或结束的时间
   */
  const relativeData = computed<RelativeData | null>(() => {
    if (!relativeOption.value) return null

    if (relativeOption.value.key === START_IN_RELATIVE) {
      return getStartRelativeData(relativeOption.value)
    } else if (relativeOption.value.key === FINISH_IN_RELATIVE) {
      return shouldTransformRelative.value
        ? getTransformedStartRelativeData(relativeOption.value)
        : getFinishRelativeData(relativeOption.value)
    }

    return null
  })

  function getStartRelativeData(option: ProgramAvailable.IntegerOption): RelativeData {
    let estimatedTime = ''
    let estimatedTimeLabel = ''
    if (remaining.value) {
      estimatedTimeLabel = i18n.global.t('Appliance.OrderProgram.EstimatedFinishTime.Text')
      const finishTimestamp = dayjs(selectedTime.value).add(remaining.value, 'seconds').valueOf()
      estimatedTime = dayjs(finishTimestamp).format('HH:mm')
    }
    // 预约时间步长
    const stepSize = option.constraints.stepsize || 60
    return {
      type: 'Start',
      estimatedTime,
      estimatedTimeLabel,
      stepSize,
      // 获取预约时间 (从【当前时间】到【预约开始】的间隔秒数)
      getTimeValue() {
        const diffSeconds = dayjs(selectedTime.value).diff(dayjs(), 'seconds')
        const value = Math.ceil(diffSeconds / stepSize) * stepSize
        return Math.max(value, 0)
      },
    }
  }

  // 将Finish in relative 转换后 显示为预计xx:xx开始
  function getTransformedStartRelativeData(option: ProgramAvailable.IntegerOption): RelativeData | null {
    if (remaining.value === 0) return null

    let estimatedTime = ''
    let estimatedTimeLabel = ''
    if (remaining.value) {
      estimatedTimeLabel = i18n.global.t('Appliance.OrderProgram.EstimatedFinishTime.Text')
      const finishTimestamp = dayjs(selectedTime.value).add(remaining.value, 'seconds').valueOf()
      estimatedTime = dayjs(finishTimestamp).format('HH:mm')
    }
    // 预约时间步长
    const stepSize = option.constraints.stepsize || 60
    return {
      type: 'TransformedStart',
      estimatedTime,
      estimatedTimeLabel,
      stepSize,
      // 获取预约时间 (从【当前时间】到【预约开始】+【程序剩余时间】的间隔秒数)
      getTimeValue() {
        const diffSeconds = dayjs(selectedTime.value).add(remaining.value, 'seconds').diff(dayjs(), 'seconds')
        const value = Math.ceil(diffSeconds / stepSize) * stepSize
        return Math.max(value, 0)
      },
    }
  }

  function getFinishRelativeData(option: ProgramAvailable.IntegerOption): RelativeData {
    let estimatedTime = ''
    let estimatedTimeLabel = ''
    if (remaining.value) {
      estimatedTimeLabel = i18n.global.t('Appliance.OrderProgram.EstimatedStartTime.Text')
      const startTimestamp = dayjs(selectedTime.value).subtract(remaining.value, 'seconds').valueOf()
      estimatedTime = dayjs(startTimestamp).format('HH:mm')
    }
    // 预约时间步长
    const stepSize = option.constraints.stepsize || 60
    return {
      type: 'Finish',
      estimatedTime,
      estimatedTimeLabel,
      stepSize,
      // 获取预约时间 (从【当前时间】到【预约结束】的间隔秒数)
      getTimeValue() {
        const diffSeconds = dayjs(selectedTime.value).diff(dayjs(), 'seconds')
        const value = Math.ceil(diffSeconds / stepSize) * stepSize
        return Math.max(value, 0)
      },
    }
  }

  /**
   * 启动预约参数
   */
  function getOrderOptions(): ProgramSelectOption[] {
    if (!relativeOption.value || !relativeData.value) throw new Error('Relative Data does not exist')

    // 启用预约参数配置
    const { key, name, unit } = relativeOption.value
    const value = relativeData.value.getTimeValue()
    const orderOptions: ProgramSelectOption[] = [{ key, name, unit, value }]
    return orderOptions
  }

  /**
   * 预约时间选择间隔 (单位: 秒)
   */
  const orderInterval = computed(() => relativeData.value?.stepSize || 60)

  return {
    selectableStartTime,
    selectableEndTime,
    initSelectableTime,
    isTodaySelected,
    selectedTime,
    setSelectTime,
    selectBeginTime,
    selectValleyTime,
    relativeData,
    orderInterval,
    getOrderOptions,
  }
}
